﻿#region

using System;
using System.Collections.Generic;
using System.Data;
using System.Data.Common;
using ylyfDataCommon.Exceptions;
using ylyfDataConnectionManager.Command;
using ylyfDataConnectionManager.Transaction;
using ylyfDataEntityConverter.Common;

#endregion

namespace ylyfDataConnectionManager.Common
{
    public abstract class HiDataBase
    {
        public HiDataBase(string ConnectionString, DbProviderFactory dbProviderFactory)
        {
            this.ConnectionString = ConnectionString;
            ProviderFactory = dbProviderFactory;
        }

        private DbProviderFactory ProviderFactory { get; }
        public string ConnectionString { get; }

        protected virtual string BuildParameter(string name)
        {
            return name;
        }

        /// <summary>
        ///     创建一个SQL参数对象
        /// </summary>
        /// <param name="name">参数名</param>
        /// <param name="value">参数值</param>
        /// <returns></returns>
        public DbParameter CreateParameter(string name, object value = null)
        {
            var parameter = ProviderFactory.CreateParameter();
            if (parameter != null)
            {
                parameter.ParameterName = BuildParameter(name);
                if (value != null)
                    parameter.Value = value;
                else
                    parameter.Value = DBNull.Value;
                return parameter;
            }
            throw new DbProviderFactoryIsWrongException();
        }


        /// <summary>
        ///     创建一个SQL参数对象
        /// </summary>
        /// <param name="name">参数名</param>
        /// <param name="value">参数值</param>
        /// <param name="dbtype">参数类型</param>
        /// <param name="size">参数大小</param>
        /// <param name="direction">参数用途</param>
        /// <param name="IsNullable">参数是否可为空</param>
        /// <returns></returns>
        public DbParameter CreateParameter(string name, object value, DbType dbtype, int size,
            ParameterDirection direction = ParameterDirection.InputOutput, bool IsNullable = true)
        {
            var parameter = CreateParameter(name, value);

            parameter.DbType = dbtype;
            parameter.Size = size;
            parameter.Direction = direction;
            parameter.IsNullable = IsNullable;
            return parameter;
        }

        /// <summary>
        ///     建立一个连接实例
        /// </summary>
        /// <returns></returns>
        public DbConnection CreateConnection()
        {
            var connection = ProviderFactory.CreateConnection();
            if (connection != null)
            {
                connection.ConnectionString = ConnectionString;
                return connection;
            }
            throw new DbProviderFactoryIsWrongException();
        }

        /// <summary>
        ///     (仅考虑兼容)创建一个数据库命令
        /// </summary>
        /// <param name="commandText">指令文本</param>
        /// <param name="CommandType">指令类型</param>
        /// <returns></returns>
        [Obsolete]
        public DbCommand CreateDbCommand(string commandText, CommandType CommandType)
        {
            var command = ProviderFactory.CreateCommand();
            if (command != null)
            {
                command.CommandText = commandText;
                command.CommandType = CommandType;
                command.Connection = CreateConnection();
                return command;
            }

            throw new DbProviderFactoryIsWrongException();
        }

        internal DbCommand CreateDbCommandWithoutConnection(string commandText, CommandType CommandType)
        {
            var command = ProviderFactory.CreateCommand();
            if (command != null)
            {
                command.CommandText = commandText;
                command.CommandType = CommandType;
                return command;
            }

            throw new DbProviderFactoryIsWrongException();
        }

        internal HiDbCommand CreateHiDbCommandWithoutConnection(string commandText, CommandType CommandType)
        {
            return new HiDbCommand(CreateDbCommandWithoutConnection(commandText, CommandType), this);
        }

        /// <summary>
        ///     建立一个数据库指令
        /// </summary>
        /// <param name="command">DbCommand实例</param>
        /// <returns></returns>
        public HiDbCommand CreateHiDbCommand(DbCommand command)
        {
            return new HiDbCommand(command, this);
        }

        /// <summary>
        ///     使用指定
        /// </summary>
        /// <param name="commandText"></param>
        /// <param name="CommandType"></param>
        /// <returns></returns>
        public HiDbCommand CreateHiDbCommand(string commandText, CommandType CommandType)
        {
            return new HiDbCommand(CreateDbCommand(commandText, CommandType), this);
        }

        public HiDbCommand CreateSqlStringCommand(string commandText)
        {
            return CreateHiDbCommand(commandText, CommandType.Text);
        }

        public HiDbCommand CreateSqlStringCommand(string commandText, params DbParameter[] Parameters)
        {
            var command = CreateHiDbCommand(commandText, CommandType.Text);
            command.Parameters.AddRange(Parameters);
            return command;
        }

        public HiDbCommand CreateStoredProcCommand(string commandText)
        {
            return CreateHiDbCommand(commandText, CommandType.StoredProcedure);
        }

        public HiDbCommand CreateStoredProcCommand(string commandText, params DbParameter[] Parameters)
        {
            var command = CreateHiDbCommand(commandText, CommandType.StoredProcedure);
            command.Parameters.AddRange(Parameters);
            return command;
        }


        internal DataAdapter GetDataAdapter()
        {
            return ProviderFactory.CreateDataAdapter();
        }

        public HiDbTransaction StartTransaction(TransactionExceptionHandler ExceptionHanler = null)
        {
            return new HiDbTransaction(this, ExceptionHanler);
        }

        #region 数据库直接执行机制

        #region ExecuteNonQuery

        public int SqlStringExecuteNonQuery(string commandText, params DbParameter[] parameters)
        {
            return ExecuteNonQuery(commandText, CommandType.Text, parameters);
        }

        public int StoredProcedureExecuteNonQuery(string commandText, params DbParameter[] parameters)
        {
            return ExecuteNonQuery(commandText, CommandType.StoredProcedure, parameters);
        }

        public int ExecuteNonQuery(string commandText, CommandType SqlType, params DbParameter[] parameters)
        {
            var command = CreateHiDbCommand(commandText, SqlType);
            using (command)
            {
                command.AddParameter(parameters);
                return command.ExecuteNonQuery();
            }
        }

        public int ExecuteNonQuery(DbCommand command)
        {
            var com = CreateHiDbCommand(command);
            return com.ExecuteNonQuery();
        }

        #endregion

        #region ExecuteDataSet

        public DataSet SqlStringExecuteDataSet(string commandText, params DbParameter[] parameters)
        {
            return ExecuteDataSet(commandText, CommandType.Text, parameters);
        }

        public DataSet StoredProcedureExecuteDataSet(string commandText, params DbParameter[] parameters)
        {
            return ExecuteDataSet(commandText, CommandType.StoredProcedure, parameters);
        }

        public DataSet ExecuteDataSet(string commandText, CommandType SqlType, params DbParameter[] parameters)
        {
            var command = CreateHiDbCommand(commandText, SqlType);
            using (command)
            {
                command.AddParameter(parameters);
                return command.ExecuteDataSet();
            }
        }

        public DataSet ExecuteDataSet(DbCommand command)
        {
            using (var com = CreateHiDbCommand(command))
            {
                return com.ExecuteDataSet();
            }
            
        }

        #endregion


        #region ExecuteDataTable

        public DataTable SqlStringExecuteDataTable(string commandText, params DbParameter[] parameters)
        {
            return ExecuteDataTable(commandText, CommandType.Text, parameters);
        }

        public DataTable StoredProcedureExecuteDataTable(string commandText, params DbParameter[] parameters)
        {
            return ExecuteDataTable(commandText, CommandType.Text, parameters);
        }

        public DataTable ExecuteDataTable(string commandText, CommandType SqlType, params DbParameter[] parameters)
        {
            var command = CreateHiDbCommand(commandText, SqlType);
            using (command)
            {
                command.AddParameter(parameters);
                return command.ExecuteDataTable();
            }
        }

        public DataTable ExecuteDataTable(DbCommand command)
        {
            var com = CreateHiDbCommand(command);
            using (com)
            {
                return com.ExecuteDataTable();
            }
        }

        #endregion

        #region ExecuteEntity

        public List<T> SqlStringExecuteEntity<T>(string commandText, EntityConverter<T> Converter = null)
            where T : new()
        {
            return ExecuteEntity(commandText, CommandType.Text, Converter);
        }

        public List<T> SqlStringExecuteEntity<T>(string commandText, EntityConverter<T> Converter = null,
            params DbParameter[] parameters) where T : new()
        {
            return ExecuteEntity(commandText, CommandType.Text, Converter, parameters);
        }

        public List<T> SqlStringExecuteEntity<T>(string commandText, params DbParameter[] parameters) where T : new()
        {
            return ExecuteEntity<T>(commandText, CommandType.Text, null, parameters);
        }

        public List<T> StoredProcedureExecuteEntity<T>(string commandText, EntityConverter<T> Converter = null)
            where T : new()
        {
            return ExecuteEntity(commandText, CommandType.StoredProcedure, Converter);
        }

        public List<T> StoredProcedureExecuteEntity<T>(string commandText,
            params DbParameter[] parameters) where T : new()
        {
            return ExecuteEntity<T>(commandText, CommandType.StoredProcedure, parameters);
        }

        public List<T> StoredProcedureExecuteEntity<T>(string commandText,
            EntityConverter<T> Converter = null, params DbParameter[] parameters) where T : new()
        {
            return ExecuteEntity(commandText, CommandType.StoredProcedure, Converter, parameters);
        }

        public List<T> ExecuteEntity<T>(string commandText, CommandType SqlType, EntityConverter<T> Converter = null)
            where T : new()
        {
            var command = CreateHiDbCommand(commandText, SqlType);
            using (command)
            {
                return command.ExecuteEntity(Converter);
            }
        }

        public List<T> ExecuteEntity<T>(string commandText, CommandType SqlType, EntityConverter<T> Converter = null,
            params DbParameter[] parameters) where T : new()
        {
            var command = CreateHiDbCommand(commandText, SqlType);
            using (command)
            {
                command.AddParameter(parameters);
                return command.ExecuteEntity(Converter);
            }
        }

        public List<T> ExecuteEntity<T>(string commandText, CommandType SqlType, DbParameter[] parameters)
            where T : new()
        {
            var command = CreateHiDbCommand(commandText, SqlType);
            using (command)
            {
                command.AddParameter(parameters);
                return command.ExecuteEntity<T>();
            }
        }

        public List<T> ExecuteEntity<T>(DbCommand command, EntityConverter<T> Converter = null) where T : new()
        {
            var com = CreateHiDbCommand(command);
            using (com)
            {
                return com.ExecuteEntity(Converter);
            }
        }

        #endregion

        #region ExecuteScalar

        public object SqlStringExecuteScalar(string commandText, params DbParameter[] parameters)
        {
            return ExecuteScalar(commandText, CommandType.Text, parameters);
        }

        public object StoredProcedureExecuteScalar(string commandText, params DbParameter[] parameters)
        {
            return ExecuteScalar(commandText, CommandType.Text, parameters);
        }


        public object ExecuteScalar(string commandText, CommandType SqlType, params DbParameter[] parameters)
        {
            using (var command = CreateHiDbCommand(commandText, SqlType))
            {
                command.AddParameter(parameters);
                return command.ExecuteScalar();
            }
        }

        #endregion

        #endregion
    }
}